<?php

namespace App\Console\AdminFormFillByFormId\FieldMakers;


use XinYaTable\Forms\Models\EloquentForm;
use XinYaTable\Forms\Models\EloquentFormCustomView;
use XinYaTable\Forms\Models\EloquentFormField;
use XinYaTable\Forms\Models\EloquentFormFieldOption;
use XinYaTable\Forms\Models\EloquentFormFilterGroup;
use XinYaTable\Forms\Models\EloquentFormFilterGroupField;
use Illuminate\Database\DatabaseManager;

abstract class BaseFormFieldMaker
{
    /**
     *
     */
    const FIELD_KEY  = '--fields--';
    /**
     *
     */
    const OPTION_KEY = '--option--';
    
    /**
     *
     */
    const FILTER_GROUP_KEY = '--filterGroup--';

    /**
     * @var int
     */
    protected $formId = 0;

    /**
     * @var float|int
     */
    protected $_mTime;
    /**
     * @var EloquentForm
     */
    protected $_eloquentForm;

    /**
     * @var EloquentFormField
     */
    protected $_eloquentFormField;

    /**
     * @var EloquentFormFieldOption
     */
    protected $_eloquentFormFieldOption;

    /**
     * @var EloquentFormCustomView
     */
    protected $_eloquentFormCustomView;
    
    /**
     * @var EloquentFormFilterGroup
     */
    protected $_eloquentFormFilterGroup;

    /**
     * @var DatabaseManager
     */
    protected $_databaseManager;

    /**
     * BaseFormFieldMaker constructor.
     */
    function __construct()
    {
        $this->_mTime = mTime();
        $this->setEloquentForm();
        $this->setEloquentFormField();
        $this->setEloquentFormFieldOption();
        $this->setDatabaseManager();
        $this->setEloquentFormCustomView();
        $this->_eloquentFormFilterGroup      = app(EloquentFormFilterGroup::class);
    }

    /**
     * @return array
     */
    abstract protected function _getFormData();

    /**
     * @return void
     */
    public function setEloquentForm()
    {
        $this->_eloquentForm = app(EloquentForm::class);
    }


    /**
     * @return void
     */
    public function setEloquentFormField()
    {
        $this->_eloquentFormField = app(EloquentFormField::class);
    }


    /**
     * @return void
     */
    public function setEloquentFormFieldOption()
    {
        $this->_eloquentFormFieldOption = app(EloquentFormFieldOption::class);
    }


    /**
     * @return void
     */
    public function setDatabaseManager()
    {
        $this->_databaseManager = app(DatabaseManager::class);
    }


    /**
     * @return void
     */
    public function setEloquentFormCustomView()
    {
        $this->_eloquentFormCustomView = app(EloquentFormCustomView::class);
    }


    /**
     * @throws \ReflectionException
     */
    public function fill()
    {
        $formMarkerName = (new \ReflectionClass($this))->getShortName();
        echo ' 开始填充表单：' . $formMarkerName . PHP_EOL;
        $this->_doFill();
        echo ' 完成填充表单：' . $formMarkerName . PHP_EOL . PHP_EOL;
    }

    /**
     * 操作填充
     */
    protected function _doFill()
    {
        $this->_databaseManager->beginTransaction();
        try {
            $formDataInfo   = $this->_getFormData();//插入表单条目并获取id
            echo ' --表单ID：' . $this->formId . PHP_EOL;
    
            //删除旧数据
            $this->_eloquentForm->newQuery()->where('id', $this->formId)->delete();
            $this->_eloquentFormField->newQuery()->where('form_id', $this->formId)->delete();
            $this->_eloquentFormCustomView->newQuery()->where('form_id', $this->formId)->delete();
            
            $formInsertData = $formDataInfo;
            unset($formInsertData[self::FIELD_KEY]);
            unset($formInsertData[self::FILTER_GROUP_KEY]);
            $this->_attachTime($formInsertData);
            $newForm = $this->_eloquentForm->newInstance()
                ->fillable(array_keys($formInsertData))
                ->fill($formInsertData);
            $newForm->save();
            if (isset($formDataInfo[self::FIELD_KEY])) {
                foreach ($formDataInfo[self::FIELD_KEY] as $key => $fieldInfo) {
                    $fieldInfo['form_id'] = $newForm->id;
                    is_string($fieldInfo['props']) && $fieldInfo['props'] = json_decode($fieldInfo['props'], true);
                    is_string($fieldInfo['validate']) && $fieldInfo['validate'] = json_decode($fieldInfo['validate'], true);
                    //插入新字段
                    $fieldInsertData = $fieldInfo;
                    unset($fieldInsertData[self::OPTION_KEY]);
                    $this->_attachTime($fieldInsertData);
                    $newField = $this->_eloquentFormField
                        ->newInstance()
                        ->fillable(array_keys($fieldInsertData))
                        ->fill($fieldInsertData);
                    $newField->save();

                    //对应选项插入
                    if (isset($fieldInfo[self::OPTION_KEY])) {
                        foreach ($fieldInfo[self::OPTION_KEY] as $optionInfo) {
                            $optionInfo['field_id'] = $newField->id;
                            $this->_eloquentFormFieldOption->newInstance()->fillable(array_keys($optionInfo))
                                ->fill($optionInfo)
                                ->save();
                        }
                    }
                    //自定义显示插入
                    if ($newField->show_column) {
                        $newCustomView = $this->_eloquentFormCustomView->newInstance()
                            ->fill(
                                [
                                    'field_id'   => $newField->id,
                                    'title'      => $newField->title,
                                    'field_name' => $newField->field_name,
                                    'field_type' => $newField->field_type,
                                    'form_id'    => $this->formId,
                                    'uid'        => -1,
                                    'order'      => $key,
                                    'is_system'  => 1,
                                    'resizable'  => $newField->props['resizable'],
                                    'editable'   => $newField->props['editable'],
                                    'sortable'   => $newField->props['sortable'],
                                ]
                            );
                        $newCustomView->save();
                    }
                }
            }
            
            //填充过滤选项
            if (isset($formDataInfo[self::FILTER_GROUP_KEY])) {
                $this->_fillFilterGroup($this->formId, $formDataInfo[self::FILTER_GROUP_KEY]);
            }
            
        } catch (\Exception $e) {
            $this->_databaseManager->rollBack();
            echo ' 填充错误：' . $e->getMessage() . PHP_EOL;
            throw $e;
        }
        $this->_databaseManager->commit();
    }
    
    /**
     * 填充过滤选项
     *
     * @param int   $formId
     * @param array $filterGroup
     */
    private function _fillFilterGroup(int $formId, array $filterGroup)
    {
        
        if (!empty($filterGroup)) {
            echo ' --表单' . $formId . '开始填充自定义筛选' . PHP_EOL;
    
            //删除过滤条件选项条目
            $filterGroupIds = $this->_eloquentFormFilterGroup->newQuery()->where('form_id', $formId)->pluck('id')->toArray();
            $filterGroupIds && EloquentFormFilterGroupField::whereIn('filter_group_id', $filterGroupIds)->delete();
            
            $this->_eloquentFormFilterGroup->newQuery()->where('form_id', $formId)->delete();
            foreach ($filterGroup as $key => $filterInfo) {
                $filterInfo['form_id'] = $formId;
                $this->_attachTime($filterInfo);
                $_newFilter            = $this->_eloquentFormFilterGroup
                    ->newInstance()
                    ->fill($filterInfo);
                $_newFilter->save();
                $_newFilter->conditions()->createMany($filterInfo['conditions'] ?? []);
            }
            echo ' --表单' . $formId . '结束填充自定义筛选' . PHP_EOL;
        }
    }
    
    /**
     * @param $data
     */
    private function _attachTime(&$data)
    {
        !isset($data['created_at']) && ($data['created_at'] = $this->_mTime);
        !isset($data['updated_at']) && ($data['updated_at'] = $this->_mTime);
    }
}